// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <nebula/io/stdio.h>

#include <iostream>

#include <nebula/core/buffer.h>


namespace nebula::io {

    //
    // StdoutStream implementation
    //

    StdoutStream::StdoutStream() : pos_(0) { set_mode(FileMode::WRITE); }

    turbo::Status StdoutStream::close() { return turbo::OkStatus(); }

    bool StdoutStream::closed() const { return false; }

    turbo::Result<int64_t> StdoutStream::tell() const { return pos_; }

    turbo::Status StdoutStream::write(const void *data, int64_t nbytes) {
        pos_ += nbytes;
        std::cout.write(reinterpret_cast<const char *>(data), nbytes);
        return turbo::OkStatus();
    }

    //
    // StderrStream implementation
    //

    StderrStream::StderrStream() : pos_(0) { set_mode(FileMode::WRITE); }

    turbo::Status StderrStream::close() { return turbo::OkStatus(); }

    bool StderrStream::closed() const { return false; }

    turbo::Result<int64_t> StderrStream::tell() const { return pos_; }

    turbo::Status StderrStream::write(const void *data, int64_t nbytes) {
        pos_ += nbytes;
        std::cerr.write(reinterpret_cast<const char *>(data), nbytes);
        return turbo::OkStatus();
    }

    //
    // StdinStream implementation
    //

    StdinStream::StdinStream() : pos_(0) { set_mode(FileMode::READ); }

    turbo::Status StdinStream::close() { return turbo::OkStatus(); }

    bool StdinStream::closed() const { return false; }

    turbo::Result<int64_t> StdinStream::tell() const { return pos_; }

    turbo::Result<int64_t> StdinStream::read(int64_t nbytes, void *out) {
        std::cin.read(reinterpret_cast<char *>(out), nbytes);
        nbytes = std::cin.gcount();
        pos_ += nbytes;
        return nbytes;
    }

    turbo::Result<std::shared_ptr<Buffer>> StdinStream::read(int64_t nbytes) {
        TURBO_MOVE_OR_RAISE(auto buffer, allocate_resizable_buffer(nbytes));
        TURBO_MOVE_OR_RAISE(int64_t bytes_read, read(nbytes, buffer->mutable_data()));
        TURBO_RETURN_NOT_OK(buffer->resize(bytes_read, false));
        buffer->zero_padding();
        // R build with openSUSE155 requires an explicit shared_ptr construction
        return std::shared_ptr<Buffer>(std::move(buffer));
    }

}  // namespace nebula::io

